/*
 * This file is part of aion-unique <aion-unique.org>.
 *
 *  aion-unique is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  aion-unique is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with aion-unique.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionemu.gameserver.model.gameobjects.instance;

import java.util.List;
import java.util.Map;

import javolution.util.FastList;
import javolution.util.FastMap;

import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.Relations;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.interfaces.IDialogRequest;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.player.RequestResponseHandler;
import com.aionemu.gameserver.model.team.alliance.PlayerAlliance;
import com.aionemu.gameserver.model.team.group.PlayerGroup;
import com.aionemu.gameserver.model.team.interfaces.ITeamMember;
import com.aionemu.gameserver.model.team.legion.Legion;
import com.aionemu.gameserver.model.templates.npcTemplate.KiskTemplate;
import com.aionemu.gameserver.model.templates.npcTemplate.eKiskType;
import com.aionemu.gameserver.model.templates.spawn.SpawnTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ATTACK_STATUS.TYPE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_DIE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_KISK_UPDATE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_LEVEL_UPDATE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_QUESTION_WINDOW;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.services.TeleportService;
import com.aionemu.gameserver.utils.PacketSendUtility;

/**
 * @author Sarynth, Lyahim
 *
 */
public class Kisk extends Npc implements IDialogRequest
{
	private static final Map<Integer, Kisk>	kiskByPlayerObjectId	= new FastMap<Integer, Kisk>().shared();

	private static Kisk getKisk(Player player)
	{
		return kiskByPlayerObjectId.get(player);
	}

	public static Kisk getKiskById(int id)
	{
		return null;
	}

	public static void onLogin(Player player)
	{
		Kisk kisk = getKisk(player);
		if (kisk != null)
			kisk.addPlayer(player);
	}

	public Kisk(int objId, SpawnTemplate spawnTemplate)
	{
		super(objId, spawnTemplate);
	}

	private int			remainingResurrections;
	private long		kiskSpawnTime;
	private ITeamMember	master;

	@Override
	public KiskTemplate getObjectTemplate()
	{
		return (KiskTemplate) super.getObjectTemplate();
	}

	/**
	 * 1 ~ race
	 * 2 ~ legion
	 * 3 ~ solo
	 * 4 ~ group
	 * 5 ~ alliance
	 * @return useMask
	 */
	public eKiskType getUseMask()
	{
		return getObjectTemplate().getKiskType();
	}

	public List<Player> getCurrentMemberList()
	{
		List<Player> list = new FastList<Player>();
		return list;
	}

	public int getCurrentMemberCount()
	{
		return getCurrentMemberList().size();
	}

	public int getMaxMembers()
	{
		return getObjectTemplate().getMembers();
	}

	public int getRemainingResurrects()
	{
		return remainingResurrections;
	}

	public int getMaxRessurects()
	{
		return getObjectTemplate().getResurrects();
	}

	public int getRemainingLifetime()
	{
		long timeElapsed = (System.currentTimeMillis() / 1000) - kiskSpawnTime;
		int timeRemaining = (int) (7200 - timeElapsed); // Fixed 2 hours 2 * 60 * 60
		return (timeRemaining > 0 ? timeRemaining : 0);
	}

	public boolean canBind(Player player)
	{
		ITeamMember master = getMaster();

		if (this.getCurrentMemberCount() >= getMaxMembers())
			return false;

		switch (getUseMask())
		{
			case ALLIANCE:
			{
				if (player.getPlayerAlliance().equals(master))
					return true;
				break;
			}
			case GROUP:
			{
				if (player.getPlayerGroup().equals(master))
					return true;
				break;
			}
			case LEGION:
			{
				if (player.getLegion().equals(master))
					return true;
				break;
			}
			case RACE:
			{
				if (master instanceof Player)
				{
					Player mplayer = (Player) master;
					if (player.getObjectTemplate().getRace().equals(mplayer.getObjectTemplate().getRace()))
						return true;
				}
				break;
			}
			case SOLO:
			{
				if (master.equals(player))
					return true;
				break;
			}
		}
		return false;
	}

	public void addPlayer(Player player)
	{
		//		if (mediator.getRelationBetweenObjects(player) == null)
		this.broadcastKiskUpdate();
		//		else
		PacketSendUtility.sendPacket(player, new SM_KISK_UPDATE(this));
		//		mediator.setRelationBetweenObjects(player, eRelationType.MEMBER);
	}

	public void removePlayer(Player player)
	{
		//		mediator.setRelationBetweenObjects(player, null);
		this.broadcastKiskUpdate();
	}

	private void broadcastKiskUpdate()
	{
		// Logic to prevent enemy race from knowing kisk information.
		for (Player member : getCurrentMemberList())
		{
			if (!this.getKnownList().knowns(member))
				PacketSendUtility.sendPacket(member, new SM_KISK_UPDATE(this));
		}
		for (VisibleObject obj : this.getKnownList().getKnownObjects().values())
		{
			if (obj instanceof Player)
			{
				Player target = (Player) obj;
				if (target.getObjectTemplate().getRace().equals(((Player) getMaster()).getObjectTemplate().getRace()))
					PacketSendUtility.sendPacket(target, new SM_KISK_UPDATE(this));
			}
		}
	}

	public void broadcastPacket(SM_SYSTEM_MESSAGE message)
	{
		for (Player member : getCurrentMemberList())
		{
			if (member != null)
				PacketSendUtility.sendPacket(member, message);
		}
	}

	public void resurrectionUsed()
	{
		remainingResurrections--;
		if (remainingResurrections <= 0)
		{
			onDespawn();
		}
		else
		{
			broadcastKiskUpdate();
		}
	}

	@Override
	public void onAttack(Creature creature, int skillId, TYPE type, int damage)
	{
		super.onAttack(creature, skillId, type, damage);
		if (this.getLifeStats().isFullyRestoredHp())
			broadcastPacket(SM_SYSTEM_MESSAGE.STR_BINDSTONE_IS_ATTACKED);
	}

	@Override
	public void onDespawn()
	{
		super.onDespawn();
		broadcastPacket(SM_SYSTEM_MESSAGE.STR_BINDSTONE_IS_REMOVED);
		removeKisk();
	}

	@Override
	public void onDie(Creature lastAttacker)
	{
		super.onDie(lastAttacker);
		broadcastPacket(SM_SYSTEM_MESSAGE.STR_BINDSTONE_IS_DESTROYED);
		removeKisk();
	}

	private void removeKisk()
	{
		for (Player member : getCurrentMemberList())
		{
			TeleportService.sendSetBindPoint(member);
			if (member.getLifeStats().isAlreadyDead())
				PacketSendUtility.sendPacket(member, new SM_DIE(false, false, 0));
			// TODO: Figure out what happens when kisk expires, but player has self-rez stone or Rebirth effect.
		}
	}

	@Override
	public void onDialogRequest(Player player)
	{

		if (player.getKisk() == this)
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_BINDSTONE_ALREADY_REGISTERED);
			return;
		}

		if (canBind(player))
		{
			RequestResponseHandler responseHandler = new RequestResponseHandler(this)
			{

				@Override
				public void acceptRequest(VisibleObject requester, Player responder)
				{
					Kisk kisk = (Kisk) requester;

					// Check again if it's full (If they waited to press OK)
					if (!kisk.canBind(responder))
					{
						PacketSendUtility.sendPacket(responder, SM_SYSTEM_MESSAGE.STR_CANNOT_REGISTER_BINDSTONE_HAVE_NO_AUTHORITY);
						return;
					}
					onBind(responder);
				}

				@Override
				public void denyRequest(VisibleObject requester, Player responder)
				{
					// Nothing Happens
				}
			};

			boolean requested = player.getResponseRequester().putRequest(SM_QUESTION_WINDOW.STR_BIND_TO_KISK, responseHandler);
			if (requested)
			{
				PacketSendUtility.sendPacket(player, new SM_QUESTION_WINDOW(SM_QUESTION_WINDOW.STR_BIND_TO_KISK, player.getObjectId()));
			}
		}
		else if (getCurrentMemberCount() >= getMaxMembers())
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CANNOT_REGISTER_BINDSTONE_FULL);
		}
		else
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CANNOT_REGISTER_BINDSTONE_HAVE_NO_AUTHORITY);
		}
	}

	public void setMaster(ITeamMember master)
	{
		this.master = master;
	}

	public ITeamMember getMaster()
	{
		return master;
	}

	@Override
	public void see(VisibleObject object)
	{
		super.see(object);
		if (object instanceof Player)
		{
			if (master instanceof Player)
			{
				if (((Player) object).getObjectTemplate().getRace().equals(((Player) getMaster()).getObjectTemplate().getRace()))
					PacketSendUtility.sendPacket(((Player) object), new SM_KISK_UPDATE(this));
			}
			else if (master instanceof PlayerGroup)
			{
				if (((Player) object).getObjectTemplate().getRace().equals(((PlayerGroup) getMaster()).getLeader().getRace()))
					PacketSendUtility.sendPacket(((Player) object), new SM_KISK_UPDATE(this));
			}
			else if (master instanceof PlayerAlliance)
			{
				if (((Player) object).getObjectTemplate().getRace().equals(((PlayerAlliance) getMaster()).getLeader().getRace()))
					PacketSendUtility.sendPacket(((Player) object), new SM_KISK_UPDATE(this));
			}
			else if (master instanceof Legion)
			{
				if (((Player) object).getObjectTemplate().getRace().equals(((Legion) getMaster()).getLeader().getPlayer().getObjectTemplate().getRace()))
					PacketSendUtility.sendPacket(((Player) object), new SM_KISK_UPDATE(this));
			}
		}
	}

	public void onBind(Player player)
	{
		if (player.getKisk() != null)
			player.getKisk().removePlayer(player);

		addPlayer(player);

		// Send Bind Point Data
		TeleportService.sendSetBindPoint(player);

		// Send System Message
		PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_BINDSTONE_REGISTER);

		// Send Animated Bind Flash
		PacketSendUtility.broadcastPacket(player, new SM_LEVEL_UPDATE(player.getObjectId(), 2, player.getObjectTemplate().getLevel()), true);
	}
	
	/* (non-Javadoc)
	 * @see com.aionemu.gameserver.model.gameobjects.NpcWhichNotGatherable#getRelation()
	 */
	@Override
	public Relations getRelation(Player player)
	{
		if (getMaster().getRace() == player.getObjectTemplate().getRace())
			return Relations.NOT_ATTACKABLE;
		else
			return Relations.ATTACKABLE;
	}
}
